﻿using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;

using System.Globalization;
using System.Text;
using System.Text.Json.Nodes;

namespace GitHubCopilotProxies.Handlers;

public class Utils
{
    public static async Task Help(HttpContext httpContext, [FromServices] EmbeddedFileProvider fileProvider)
    {
        var fileInfo = fileProvider.GetFileInfo("help.html");
        var ifModifiedSinceStr = httpContext.Request.GetTypedHeaders().IfModifiedSince?.ToString("r", CultureInfo.InvariantCulture);
        var lastModifiedStr = fileInfo.LastModified.ToString("r", CultureInfo.InvariantCulture);
        if (string.Equals(ifModifiedSinceStr, lastModifiedStr, StringComparison.OrdinalIgnoreCase))
        {
            httpContext.Response.StatusCode = StatusCodes.Status304NotModified;
            return;
        }
        httpContext.Response.ContentType = HtmlContentType;
        var typedHeaders = httpContext.Response.GetTypedHeaders();
        typedHeaders.CacheControl = new() { Public = true, MaxAge = TimeSpan.FromHours(1) };
        typedHeaders.LastModified = fileInfo.LastModified;
        using var stream = fileInfo.CreateReadStream();
        await stream.CopyToAsync(httpContext.Response.Body, httpContext.RequestAborted);
        await httpContext.Response.CompleteAsync();
    }

    internal static (HashSet<string> modelIds, string modelJson) ReloadModels(SystemConfig config, EmbeddedFileProvider fileProvider)
    {
        var modelIds = new HashSet<string>();
        var enabledIds = new HashSet<string>();
        var fileInfo = fileProvider.GetFileInfo("models.json");
        using var stream = fileInfo.CreateReadStream();
        var jsonObj = JsonObject.Parse(stream)!;
        var models = jsonObj["data"]!.AsArray().AsEnumerable().Cast<JsonObject>();
        foreach (var model in models)
        {
            if (model["capabilities"]!.AsObject()!["type"]!.ToString() != "chat") continue;
            var modelId = model!["id"]!.ToString();
            modelIds.Add(modelId);
            if (config.ChatCompletions!.ContainsKey(modelId))
            {
                var chatModel = config.ChatCompletions[modelId];
                var name = chatModel.Name;
                model["name"] = name;
                model["model_picker_enabled"] = chatModel.Enabled ?? true;
                enabledIds.Add(modelId);
                if (modelId.StartsWith("gpt") || modelId.StartsWith("o1") || modelId.StartsWith("o3"))
                    foreach (var similar in models.Where(m => 
                        m["id"]!.ToString().StartsWith(modelId) &&
                        m != model && m["capabilities"]?["type"]?.ToString() == "chat"))
                    {
                        similar["name"] = name;
                        enabledIds.Add(similar["id"]!.ToString());
                    }
            }
            if (enabledIds.Contains(modelId) == false)
            {
                model["model_picker_enabled"] = false;
                model["policy"] = new JsonObject() { { "state", "disabled" } };
            }
        }
        return (modelIds, jsonObj.ToJsonString(AppJsonSerializerContext.Default.Options));
    }
    public static async Task GetModels(HttpContext httpContext, [FromKeyedServices("Models")] string models)
    {
        await httpContext.ResponseJsonAsync(models);
    }

    public static async Task GetPing(HttpContext httpContext)
    {
        httpContext.Response.ContentType = TextContentType;
        await httpContext.Response.WriteAsync("OK", Encoding.UTF8, httpContext.RequestAborted);
        await httpContext.Response.CompleteAsync();
    }

    public static async Task GetAgents(HttpContext httpContext)
    {
        await httpContext.ResponseJsonAsync("""{"agents":[]}""");
    }

    public static async Task GetV3meta(HttpContext httpContext)
    {
        await httpContext.ResponseJsonAsync("{}");
    }

    public static async Task GetCliv3(HttpContext httpContext)
    {
        httpContext.ResponseWithXOAuthScopes();
        const string jsonInfo = """{"current_user_url":"https://api.github.com/user","current_user_authorizations_html_url":"https://github.com/settings/connections/applications{/client_id}","authorizations_url":"https://api.github.com/authorizations","code_search_url":"https://api.github.com/search/code?q={query}{&page,per_page,sort,order}","commit_search_url":"https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}","emails_url":"https://api.github.com/user/emails","emojis_url":"https://api.github.com/emojis","events_url":"https://api.github.com/events","feeds_url":"https://api.github.com/feeds","followers_url":"https://api.github.com/user/followers","following_url":"https://api.github.com/user/following{/target}","gists_url":"https://api.github.com/gists{/gist_id}","hub_url":"https://api.github.com/hub","issue_search_url":"https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}","issues_url":"https://api.github.com/issues","keys_url":"https://api.github.com/user/keys","label_search_url":"https://api.github.com/search/labels?q={query}&repository_id={repository_id}{&page,per_page}","notifications_url":"https://api.github.com/notifications","organization_url":"https://api.github.com/orgs/{org}","organization_repositories_url":"https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}","organization_teams_url":"https://api.github.com/orgs/{org}/teams","public_gists_url":"https://api.github.com/gists/public","rate_limit_url":"https://api.github.com/rate_limit","repository_url":"https://api.github.com/repos/{owner}/{repo}","repository_search_url":"https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}","current_user_repositories_url":"https://api.github.com/user/repos{?type,page,per_page,sort}","starred_url":"https://api.github.com/user/starred{/owner}{/repo}","starred_gists_url":"https://api.github.com/gists/starred","topic_search_url":"https://api.github.com/search/topics?q={query}{&page,per_page}","user_url":"https://api.github.com/users/{user}","user_organizations_url":"https://api.github.com/user/orgs","user_repositories_url":"https://api.github.com/users/{user}/repos{?type,page,per_page,sort}","user_search_url":"https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"}""";
        await httpContext.ResponseJsonAsync(jsonInfo);
    }
}
